﻿// Copyright (c) 2010 Dan Popick

// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Xml;
using System.Xml.Serialization;

// Deserialization adapted from Craig Andera:  
// http://alt.pluralsight.com/wiki/default.aspx/Craig/XmlSerializerSectionHandler.html

namespace Open.Web.Stijl.Configuration
{
    public class XmlSectionHandler: IConfigurationSectionHandler
    {
        public object Create(object parent, object configContext, XmlNode section)
        {
            XmlAttribute typeAttr = section.Attributes["type"];
            if (typeAttr == null)
                throw new InvalidOperationException("'type' attribute not specified for section " + section.Name);

            Type t = Type.GetType(typeAttr.Value);
            if (t == null)
                throw new TypeLoadException(String.Format("unable to find type '{0}' for section {1} ", typeAttr.Value, section.Name));

            // push the section's contents into a new node which is named after the type
            // XmlSerializer expects this
            // NOTE: this will break properties marked with XmlAttributeAttribute, as we're
            // only copying the nodes here. It's doable, but not necessary (yet)
            XmlDocument newDoc = new XmlDocument();
            XmlNode root = newDoc.CreateElement(t.Name);
            foreach (XmlNode child in section.ChildNodes)
                root.AppendChild(newDoc.ImportNode(child, true));

            try
            {
                XmlSerializer ser = new XmlSerializer(t);
                return ser.Deserialize(new XmlNodeReader(root));
            }
            catch (Exception ex)
            {
                throw new FormatException("Failed to deserialize the config section " + section.Name, ex);
            }
        }
    }
}
